Last week, we talked about some convenient functions in Java. Here is a library which is a mother of all convenient functions. I met Google Guava about 2-3 years ago when I was working on MAWA Analyzer project and I have been staying a huge fan of it. Guava is a well-designed API which is meant to simplify your coding by introducing functions related to Collections, Functional Programming, Concurrency, Ordering, String Manipulations, IO Utilities, Reflection Utils, etc. Codes were advised and reviewed by Joshua Bloch, the author of Effective Java, which follows many of the patterns in the book such as the static factory, builder, immutability, null-checks, etc. Guava was open sourced as early as in 2007. The API uses Java Generics as Java 5 was already available at the time. Guava just makes the coding super exciting and fun!
Google Guava version 20.0 is out on October 28, 2016. See here to resolve dependency via Maven or Gradle. The listed items below are from Guava which I find convenient often times. They are mostly, if not all, supported in version 19.0 and up. In case you are still unsure on their usage, refer to their Java Doc. I strongly recommend at least have a look at their API doc. They just have so many functions I won’t be able to cover them all here. The functions introduced below are the ones I use and found themselves useful.
This item is probably what made Guava famous. You can name a data structure to define using their static factory methods. There are ways to define structures:
Lists.newArrayList();
List<String> theseElements = Lists.newArrayList("alpha", "beta", "gamma");
List<Type> exactly100 = Lists.newArrayListWithCapacity(100);
Note: if the list is immutable, consider ImmutableList.reverse() instead.
List<Type> reversedList = Lists.reverse(theList);
Returns a view of the underlying list, partitioned into chunks of the specified size.
List<List<Integer>> parts = Lists.partition(countUp, 2);
remove all null values from a collection
List<String> values = Lists.newArrayList("a", null, "b", "c");
Iterable<String> withoutNulls = Iterables.filter(values, Predicates.notNull());
create immutable List directly
ImmutableList<String> immutableList = ImmutableList.of("a", "b", "c");
create immutable List from a standard collection
List<String> mutableList = Lists.newArrayList();
ImmutableList<String> immutableList = ImmutableList.copyOf(mutableList);
Using above copy using builder
List<String> mutableList = Lists.newArrayList();
ImmutableList<String> immutableList =
ImmutableList.<String> builder().addAll(mutableList).build();
Set<Type> aSet = Sets.newHashSet();
Sets support intersection as follows,
Set<String> wordsWithPrimeLength = ImmutableSet.of("one", "two", "three", "six", "seven", "eight");
Set<String> primes = ImmutableSet.of("two", "three", "five", "seven");
SetView<String> intersection = Sets.intersection(primes, wordsWithPrimeLength); // contains "two", "three", "seven"
// I can use intersection as a Set directly, but copying it can be more efficient if I use it a lot.
return intersection.immutableCopy();
Sets also support cartesianProduct or powerSet function, {: style=”margin-bottom: .5em; margin-top: 1em;”}yy
Set<String> animals = ImmutableSet.of("gerbil", "hamster");
Set<String> fruits = ImmutableSet.of("apple", "orange", "banana");
Set<List<String>> product = Sets.cartesianProduct(animals, fruits);
// {"gerbil", "apple"}, {"gerbil", "orange"}, {"gerbil", "banana"},
// {"hamster", "apple"}, {"hamster", "orange"}, {"hamster", "banana"}
Set<Set<String>> animalSets = Sets.powerSet(animals);
// {}, {"gerbil"}, {"hamster"}, {"gerbil", "hamster"}
create immutable Set directly
ImmutableSet<String> immutableSet = ImmutableSet.of("a", "b", "c");
create immutable Set from a standard collection
Set<String> mutableSet = Sets.newHashSet();
ImmutableSet<String> immutableSet = ImmutableSet.copyOf(mutableSet);
Using above copy using builder
Set<String> mutableSet = Sets.newHashSet();
ImmutableSet<String> immutableSet =
ImmutableSet.<String> builder().addAll(mutableSet).build();
Maps.newLinkedHashMap();
difference:
Map<String, Integer> left = ImmutableMap.of("a", 1, "b", 2, "c", 3);
Map<String, Integer> right = ImmutableMap.of("b", 2, "c", 4, "d", 5);
MapDifference<String, Integer> diff = Maps.difference(left, right);
diff.entriesInCommon(); // {"b" => 2}
diff.entriesDiffering(); // {"c" => (3, 4)}
diff.entriesOnlyOnLeft(); // {"a" => 1}
diff.entriesOnlyOnRight(); // {"d" => 5}
create immutable Map directly
ImmutableMap<String, String> imutableMap =
ImmutableMap.of("k1", "v1", "k2", "v2", "k3", "v3");
create immutable Map from a standard collection
Map<String, String> mutableMap = Maps.newHashMap();
ImmutableMap<String, String> imutableMap = ImmutableMap.copyOf(mutableMap);
Using above copy using builder
Map<String, String> mutableMap = Maps.newHashMap();
ImmutableMap<String, String> imutableMap =
ImmutableMap.<String, String> builder().putAll(mutableMap).build();
SortedMap:
ImmutableSortedMap<String, Integer> salary = new ImmutableSortedMap
.Builder<String, Integer>(Ordering.natural())
.put("John", 1000)
.put("Jane", 1500)
.put("Adam", 2000)
.put("Tom", 2000)
.build();
Ordering is Guava’s “fluent” Comparator class, which can be used to build complex comparators and apply them to collections of objects. It’s basically a “comparator” instance. Examples are below:
assertTrue(byLengthOrdering.reverse().isOrdered(list));
natural()
Collections.sort(toSort, Ordering.natural());
assertTrue(Ordering.natural().isOrdered(toSort));
usingtoString()
List<Integer> toSort = Arrays.asList(1, 2, 11);
Collections.sort(toSort, Ordering.usingToString());
Ordering<Integer> expectedOrder = Ordering.explicit(Lists.newArrayList(1, 11, 2));
assertTrue(expectedOrder.isOrdered(toSort));
Sort then Binary Search
List<Integer> toSort = Arrays.asList(1, 2, 11);
Collections.sort(toSort, Ordering.usingToString());
int found = Ordering.usingToString().binarySearch(toSort, 2);
find min/max without sort
List<Integer> toSort = Arrays.asList(2, 1, 11, 100, 8, 14);
int found = Ordering.usingToString().min(toSort);
assertThat(found, equalTo(1));
Chaining 2 orderings
List<Integer> toSort = Arrays.asList(3, 5, 4, 1, 2);
Collections.sort(toSort, Ordering.natural().reverse());
nulls first
List<Integer> toSort = Arrays.asList(3, 5, 4, null, 1, 2);
Collections.sort(toSort, Ordering.natural().nullsFirst());
assertThat(toSort.get(0), nullValue());
Until now, Strings are usually handled by company’s own implementation of “StringUtils”. This is typically a bad idea as there are libraries out there that handle most of the job. Trust these libraries for 2 main reasons. First, hundreds of people have laid their eyes on the codes online (open-sourced libraries). Second, a lot of people are using them. There are other options for StringUtils than Guava. There is Apache Commons. The project started n 2002. Somewhat Old. Still, has quite useful libraries. I love their StringBuilder/StringWriter functions. Guava has their lovely ones too such as Joiner, Splitter and especially CharMatcher. See below:
Joiner:
Joiner joiner = Joiner.on("; ").skipNulls();
return joiner.join("Harry", null, "Ron", "Hermione");
Or you can just straight apply,
Joiner.on(",").join(Arrays.asList(1, 5, 7)); // returns "1,5,7"
Splitter:
Splitter.on(',')
.trimResults()
.omitEmptyStrings()
.split("foo,bar,, qux");
CharMatcher, this is my favourite, I felt like writing a poem when I first used it:
private CharMatcher FILTER = CharMatcher.anyOf("-.;").precomputed();
You can run one of the following functions,
String noControl = CharMatcher.JAVA_ISO_CONTROL.removeFrom(string); // remove control characters
String theDigits = CharMatcher.DIGIT.retainFrom(string); // only the digits
String spaced = CharMatcher.WHITESPACE.trimAndCollapseFrom(string, ' ');
// trim whitespace at ends, and replace/collapse whitespace into single spaces
String noDigits = CharMatcher.JAVA_DIGIT.replaceFrom(string, "x"); // mark x all digits
String lowerAndDigit = CharMatcher.JAVA_DIGIT.or(CharMatcher.JAVA_LOWER_CASE).retainFrom(string);
// eliminate all characters that aren't digits or lowercase
Charsets:
bytes = string.getBytes(Charsets.UTF_8);
Your traditional compareTo method might look like this:
1
2
3
4
5
6
7
8
9
10
11
@Override
public int compareTo(User that) {
int result = 0;
result = userId != null ? userId.compareTo(that.getUserId()) : result;
result = result == 0 ? personName.compareTo(that.getPersonName()) : result;
result = result == 0 ? age.compareTo(that.getAge()) : result;
result = result == 0 ? address.compareTo(that.getAddress()) : result;
return result;
}
Now, above can be shortened using Guava like this.
1
2
3
4
5
6
7
8
public int compareTo(User that) {
return ComparisonChain.start()
.compare(userId, that.getUserId())
.compare(personName, that.getPersonName(), Ordering.natural().nullsFirst())
.compare(age, that.getAge(), Ordering.natural().nullsFirst())
.compare(address, that.getAddress())
.result();
}
Look how clean it is. It’s also just beautiful that you can apply Ordering in this chain. Ordering is basically used as a comparator.
Don’t use your own Utils functions. Use only ones applicable specific to your project. There are many other options for Utils. However, at least for Java, Big 2 Java Collections Library is, Apache Commons and Google Guava. These libraries use names very well made usage so much easier and fun. There will be a time where you can solve your issues using one of these libraries, trust me Make sure you check them first and see if you can incorporate these libraries into your project. Also, please check out my github for test cases on Guava library. I have mostly covered examples I discussed in this blog. I may have added one or two more than what has covered here actually hehe